# _*_ encoding: utf-8 _*_
try:
    import xml.etree.cElementTree as ET
except ImportError:
    import xml.etree.ElementTree as ET
import os
import optparse


def load_road_structure(filename):
    road_structure = {}
    for event, node in ET.iterparse(filename):
        if event == 'end':
            if node.tag == 'edge':
                id = node.attrib['id']
                # ignore the internal edges
                if 'function' in node.attrib and node.attrib['function'] == 'internal':
                    continue
                if id.startswith(":"):
                    continue
                attrib = {}
                # print id
                attrib.setdefault('length', float(node[0].attrib['length']))
                # attrib.setdefault('type', node.attrib['type'])
                attrib.setdefault('speed', float(node[0].attrib['speed']))
                road_structure.setdefault(id, attrib)
    return road_structure


def parse(line):
    elements = line.strip().split(',')
    elements[1] = int(float(elements[1]))
    elements[2] = float(elements[2])
    elements[3] = float(elements[3])
    elements[6] = float(elements[6])
    elements[7] = float(elements[7])
    edge = elements[8].strip().split('_')
    elements[8] = "_".join(edge[:-1])
    return elements


class RoadInformationExtractor:

    def __init__(self, net_file, gps_file, save_file):
        assert os.path.isfile(net_file)
        assert os.path.isfile(gps_file)
        # assert os.path.isfile(save_file) is False
        self.road_structure = load_road_structure(net_file)
        self.gps_file = gps_file
        self.vehicles = {}
        self.road_info = {}
        self.save_file = save_file

    def start(self):
        assert self.road_structure is not None
        self.run()

    def run(self):
        with open(self.gps_file, "rb") as f:
            block = {}
            current_time = -1
            for line in f:
                item = parse(line)
                if current_time != -1 and current_time != item[1]:
                    self.process(current_time, block)
                    del block
                    block = {}
                current_time = item[1]
                block[item[0]] = item
        self.write_road_info()

    def dealWithNew(self, real_info, newEdge):
        if newEdge in self.road_structure:
            real_info.setdefault(newEdge, [0, 0, 0])
            real_info[newEdge][0] += 1
            real_info[newEdge][1] += 1
            return real_info

    def dealWithOld(self, real_info, oldEdge):
        if oldEdge in self.road_structure:
            real_info.setdefault(oldEdge, [0, 0, 0])
            real_info[oldEdge][2] += 1
            return real_info

    def process(self, timestamp, block):
        real_info = {}
        cached = []
        for vehicleID in self.vehicles:
            item = self.vehicles[vehicleID]
            oldEdge = item[-2]
            if vehicleID in block:
                newEdge = block[vehicleID][-2]
                if oldEdge != newEdge: # move to new road
                    self.dealWithNew(real_info, newEdge)
                    self.dealWithOld(real_info, oldEdge)
                else: # the same road
                    real_info.setdefault(oldEdge, [0, 0, 0])
                    real_info[oldEdge][1] += 1
            else: # arrive
                self.dealWithOld(real_info, oldEdge)
                cached.append(vehicleID)
        for vehicleID in block:
            item = block[vehicleID]
            if vehicleID not in self.vehicles: # new inserted
                self.dealWithNew(real_info, item[-2])
            self.vehicles[vehicleID] = block[vehicleID]
        for vehicleID in cached:
            self.vehicles.pop(vehicleID)
        del cached
        for edge in real_info:
            if edge not in self.road_info:
                self.road_info.setdefault(edge, [])
            item = [timestamp]
            item.extend(real_info[edge])
            self.road_info[edge].append(item)

    def write_road_info(self):
        with open(self.save_file, "wb") as f:
            cached = []
            for edge in self.road_info:
                for item in self.road_info[edge]:
                    cached.append("{0},{1},{2},{3},{4}\n".format(edge, item[0], item[1], item[2], item[3]))
                f.writelines(cached)
                del cached
                cached = []


def get_options(args=None):
    optparser = optparse.OptionParser()
    optparser.add_option("-n", "--net", dest="net_file", help="the road net work")
    optparser.add_option("-g", "--gps", dest="gps_file", help="the gps file in csv format")
    optparser.add_option("-o", "--output", dest="output", help="the output file")
    (options, args) = optparser.parse_args(args=args)
    if not options.net_file or not options.gps_file or not options.output:
        optparser.print_help()
        exit(1)
    return options


def main(options=None):
    # net_file = "../../data/1109/hangzhou_main_road.net.xml"
    # gps_file = "../../data/1109/11011607.gps.csv"
    # save_file = "../../data/1109/11011607.road.txt"
    net_file = options.net_file
    gps_file = options.gps_file
    save_file = options.output
    extractor = RoadInformationExtractor(net_file, gps_file, save_file)
    extractor.start()

if __name__ == '__main__':
    main(get_options())
